1 /*
2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021
3 License:   [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License].
4 Authors: Marcelo S. N. Mancini
5 
6 	Copyright Marcelo S. N. Mancini 2018 - 2021.
7 Distributed under the CC BY-4.0 License.
8    (See accompanying file LICENSE.txt or copy at
9 	https://creativecommons.org/licenses/by/4.0/
10 */
11 
12 module hip.api.internal;
13 import hip.api;
14 
15 ///Used for creating a function which will generate an overload to call a function pointer
16 struct Overload
17 {
18 	string targetName;
19 }
20 
21 version(WebAssembly) version = ErrorOnLoadSymbol;
22 version(PSVita) version = ErrorOnLoadSymbol;
23 
24 version(ScriptAPI) version = LoadFunctionPointers;
25 
26 
27 version(LoadFunctionPointers)
28 {
29 	__gshared void* _dll;
30 	void initializeHip()
31 	{
32 		version(ErrorOnLoadSymbol)
33 		{
34 			assert(false, "Cannot load symbols in this version.");
35 		}
36 		else
37 		{
38 			version(Windows){_dll = GetModuleHandle(null);}
39 			else
40 			{
41 				import core.sys.posix.dlfcn:dlopen, RTLD_NOW;
42 				_dll = dlopen(null, RTLD_NOW);
43 			}
44 			import core.stdc.stdio;
45 			if(_dll == null)
46 				printf("Could not load GetModuleHandle(null)\n");
47 			hipDestroy = cast(typeof(hipDestroy))_loadSymbol(_dll, "hipDestroy");
48 			if(hipDestroy == null)
49 				printf("Fatal error: could not load hipDestroy\n");
50 		}
51 	}
52 }
53 version(Windows)
54 {
55 	@nogc nothrow extern(Windows)
56 	{
57 		void* GetModuleHandleW(const(wchar)* str);
58 		void* GetProcAddress(void* mod, const(char)* func);
59 		void* FreeLibrary(void* lib);
60 		uint GetLastError();
61 	}
62 	alias GetModuleHandle = GetModuleHandleW;
63 	alias _loadSymbol = GetProcAddress;
64 }
65 
66 version(Posix)
67 {
68 	import core.sys.posix.dlfcn:dlsym;
69 	alias _loadSymbol = dlsym;
70 }
71 enum bool isFunctionPointer(alias T) = is(typeof(*T) == function);
72 
73 /**
74 *	Prefer using that function instead of loadSymbol, as compile
75 *	time sequences reduced the binary size in almost 100kb.
76 *
77 *	The problem is not yet solved, but it is a lot better than doing several
78 *	template instantiations
79 */
80 void loadSymbols(Ts...)()
81 {
82 	static foreach(s; Ts)
83 		s = cast(typeof(s))_loadSymbol(_dll, s.stringof);
84 }
85 
86 /**
87 *	This function will load all function pointers defined in the module passed.
88 */
89 void loadModuleFunctionPointers(alias targetModule, string exportedClass = "")()
90 {
91 	string prefix = "";
92 	string importedFunctionName;
93 	static if(exportedClass != "")
94 		prefix = exportedClass~"_";
95 	static foreach(member; __traits(allMembers, targetModule))
96 	{{
97 		alias f = __traits(getMember, targetModule, member);
98 		static if(isFunctionPointer!(f))
99 		{
100 			importedFunctionName = prefix~member~'\0';
101 			if(f is null)
102 			{
103 				f = cast(typeof(f))_loadSymbol(_dll, importedFunctionName.ptr);
104 				if(f is null)
105 				{
106 					import core.stdc.stdio;
107 					printf(f.stringof~" wasn't able to load (tried with %s)\n", importedFunctionName.ptr);
108 				}
109 			}
110 		}
111 	}}
112 }
113 
114 
115 string generateFunctionDefinitionFromFunctionPointer(alias funcPointerSymbol, string name)()
116 {
117 	import std.traits;
118 	string params;
119 	string identifiers;
120 
121 	bool isFirst = true;
122 	alias storage = ParameterStorageClassTuple!funcPointerSymbol;
123 	static foreach(i, p; Parameters!funcPointerSymbol)
124 	{
125 		if(!isFirst)
126 		{
127 			params~= ",";
128 			identifiers~= ",";
129 		}
130 		else
131 			isFirst = false;
132 		if(storage[i] != ParameterStorageClass.none)
133 			params~= storage[i].stringof["ParameterStorageClass.".length..$-1] ~" "; //Remove enum namespace and the "_"
134 		params~= p.stringof ~ " _"~i.stringof;
135 		identifiers~= "_"~i.stringof;
136 	}
137 
138 	return (ReturnType!funcPointerSymbol).stringof ~ " "~ name ~ "("~params 
139 	~"){return "~ funcPointerSymbol.stringof ~ "("~identifiers ~ ");}";
140 
141 }
142 
143 mixin template OverloadsForFunctionPointers(alias targetModule)
144 {
145 	import std.traits;
146 	static foreach(symbol; getSymbolsByUDA!(targetModule, Overload))
147 	{
148 		pragma(msg, generateFunctionDefinitionFromFunctionPointer!(symbol, getUDAs!(symbol, Overload)[0].targetName));
149 		mixin(generateFunctionDefinitionFromFunctionPointer!(symbol, getUDAs!(symbol, Overload)[0].targetName));
150 	}
151 }
152 
153 mixin template ExpandClassFunctionPointers(alias targetClass)
154 {
155 	import hip.api.internal: isFunctionPointer;
156 
157 	static foreach(mem; __traits(allMembers, targetClass))
158 	{
159 		static if(isFunctionPointer!(__traits(getMember, targetClass, mem)))
160 		{
161 			mixin(__traits(getVisibility, __traits(getMember, targetClass, mem)), " alias ", mem, " = ", __traits(identifier, targetClass), ".", mem,";");
162 		}
163 	}
164 }
165 template Flag(string f)
166 {
167 	enum Flag : bool
168 	{
169 		No = false,
170 		Yes = true
171 	}
172 }
173 
174 alias UseExportedClass = Flag!"UseExportedClass";
175 
176 void loadClassFunctionPointers(alias targetClass, 
177 	UseExportedClass useExported = UseExportedClass.No, 
178 	string exportedClass = "")
179 ()
180 {
181 	string prefix = "";
182 	string importedFunctionName;
183 
184 	version(ErrorOnLoadSymbol)
185 	{
186 		assert(false, "Cannot load symbols in this version.");
187 	}
188 	else
189 	{
190 		string nExportedClass = exportedClass;
191 		static if(useExported)
192 		{
193 			static if(exportedClass == "")
194 				nExportedClass = targetClass.stringof;
195 			prefix = nExportedClass~"_";
196 		}
197 		static foreach(member; __traits(allMembers, targetClass))
198 		{{
199 			alias f = __traits(getMember, targetClass, member);
200 			static if(isFunctionPointer!(f))
201 			{
202 				importedFunctionName = prefix~member~'\0';
203 				f = cast(typeof(f))_loadSymbol(_dll, importedFunctionName.ptr);
204 				if(f is null)
205 				{
206 					import core.stdc.stdio;
207 					printf(f.stringof ~ " wasn't able to load (tried with %s)\n", importedFunctionName.ptr);
208 				}
209 			}
210 		}}
211 	}
212 }
213 
214 template loadSymbolsFromExportD(string exportedClass, Ts...)
215 {
216 	version(ErrorOnLoadSymbol)
217 	{
218 		enum impl = "";
219 	}
220 	else
221 	{
222 		enum impl = ()
223 		{
224 			enum e = '"'~exportedClass~"_\"";
225 			string ret;
226 			static foreach(i, s; Ts)
227 			{
228 				ret~= s.stringof ~"= cast(typeof("~s.stringof~ " ))_loadSymbol(_dll, ("~e~"~\""~s.stringof~"\\0\").ptr);";
229 				if(s.stringof is null)
230 				{
231 					import core.stdc.stdio;
232 					printf("Could not load "~s.stringof~" (tried with "~ e~s.stringof~")\n");
233 				}
234 			}
235 			return ret;
236 		}();
237 	}
238 
239 	enum loadSymbolsFromExportD = impl;
240 }